<?php
namespace App;
use Exception;

class Qllb
{
    private $outputString = "";
    private $output;
    private $MAX_CYCLES = 10000;
    private $os = array();
    private $pc = 0;
    private $code = "";
    private $trace = "";

    public function run($code)
    {
        $mem = array();
        for ($i = 0; $i < 1000; $i++) {
            $mem[$i] = 0;
        }
        $cnt = 0;
        try {
            while ($this->pc < strlen($code)) {
                $ins = $code[$this->pc++];
                if ($cnt++ > $this->MAX_CYCLES) throw new Exception("循环太多次了,代码是不是死循环了呢");
                switch ($ins) {
                    case '0':
                        $this->push(0);
                        break;
                    case '1':
                        $this->push(1);
                        break;
                    case '2':
                        $this->push(2);
                        break;
                    case '3':
                        $this->push(3);
                        break;
                    case '4':
                        $this->push(4);
                        break;
                    case '5':
                        $this->push(5);
                        break;
                    case '6':
                        $this->push(6);
                        break;
                    case '7':
                        $this->push(7);
                        break;
                    case '8':
                        $this->push(8);
                        break;
                    case '9':
                        $this->push(9);
                        break;
                    case '+':
                        $this->push($this->pop() + $this->pop());
                        break;
                    case '-':
                        $a = $this->pop();
                        $b = $this->pop();
                        $this->push($b - $a);
                        break;
                    case '*':
                        $this->push($this->pop() * $this->pop());
                        break;
                    case '/':
                        $a = $this->pop();
                        $b = $this->pop();
                        $this->push(intval($b / $a));
                        break;
                    case 'p':
                        $this->emitOutput($this->pop());
                        break;
                    case 'P':
                        $this->emitOutput(chr($this->pop()));
                        break;
                    case 'm':
                        $this->pc += $this->pop();
                        break;
                    case 'i':
                        $offset = $this->pop();
                        if ($this->pop() == 0) $this->pc += $offset;
                        break;
                    case 'g':
                        $this->pc = $this->pop();
                        break;
                    case 'd':
                        $this->pop();
                        break;
                    case 'y':
                        $a = $this->pop();
                        $this->push($a);
                        $this->push($a);
                        break;
                    case 'e':
                        break;
                    case 'r':
                        $addr = $this->pop();
                        if ($addr < 0 || $addr >= 1000) throw new Exception("读内存超出边界@" . $addr);
                        $this->push($mem[$addr]);
                        break;
                    case 's':

                        $addr = $this->pop();
                        if ($addr < 0 || $addr >= 1000) throw new Exception("写内存超出边界@" . $addr);
                        $mem[$addr] = $this->pop();
                    case ' ':
                        break;
                    default:
                        throw new Exception("无法识别指令 " . $ins);
                }
                if ($ins == 'e') break;
                if ($this->pc < 0 || $this->pc >= strlen($code))
                    throw new Exception("程序的执行指针超过了代码的边界");
            }
        } catch (Exception $e) {
            $this->emitOutput("错误:" . $e->getMessage());
        }
    }

    private function push($v)
    {
        if ($v > 2147483647 || $v < -2147483648) throw new Exception("整数越界");
        array_push($this->os, $v);
    }

    private function pop()
    {
        if (count($this->os) == 0) throw new Exception("堆中已经没有任何元素了");
        return array_pop($this->os);
    }

    private function emitOutput($txt)
    {
        $this->outputString .= $txt;
    }

    public function output()
    {
        return $this->outputString;
    }
}

?>
